package tr.gov.tubitak.bilgem.esya.certselector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.security.pkcs11.wrapper.CK_TOKEN_INFO;
import sun.security.pkcs11.wrapper.PKCS11Exception;
import tr.gov.tubitak.uekae.esya.api.common.util.StringUtil;
import tr.gov.tubitak.uekae.esya.api.common.util.bag.Pair;
import tr.gov.tubitak.uekae.esya.api.smartcard.apdu.APDUSmartCard;
import tr.gov.tubitak.uekae.esya.api.smartcard.pkcs11.*;

import java.io.IOException;
import java.util.ArrayList;

/**
 * Created by IntelliJ IDEA.
 * User: ramazan.girgin
 * Date: 14.11.2011
 * Time: 11:28
 * To change this template use File | Settings | File Templates.
 */
public class ESmartCardManager {
    private static ESmartCardManager instance = null;
    private static Logger logger = LoggerFactory.getLogger(ESmartCardManager.class);

    public static void clear()
    {
        if(instance != null)
        {
            ArrayList<EBasicSmartCard> bsds = instance.getBasicSmartCards();
            for (EBasicSmartCard bsd : bsds) {
                try {
                    BaseSmartCard bsdC = bsd.getBaseSmartCard();
                    bsdC.closeSession();
                } catch (SmartCardException e) {
                    //e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                }
            }
            instance = null;
        }

    }


    private ESmartCardManager(){
        init();
    };

    private void init()
    {
        String[] cardTerminals =getCardTerminals();
        constructCardList(cardTerminals);
    }

    public String[] getCardTerminals()
    {
        try {
            logger.debug("SmartOp.getCardTerminals-cagirilacak");
            String[] cardTerminals = SmartOp.getCardTerminals();
            logger.debug("SmartOp.getCardTerminals-cagirildi. Gelenler = ");
            for (String cardTerminal : cardTerminals) {
                logger.debug("Card Terminal :"+cardTerminal);
            }
            return cardTerminals;
        } catch (SmartCardException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            logger.error("SmartOp.getCardTerminals Hata ",e);
            return null;
        }
    }

    private void constructCardList(String[] cardTerminals)
    {
        if(basicSmartCards == null)
        {
            basicSmartCards = new ArrayList<EBasicSmartCard>();
        }
        if(cardTerminals == null)
        {
            return;
        }

        for (int k=0;k<cardTerminals.length;++k)
        {
            try
            {
                BaseSmartCard bsc = null;
                String cardTerminal = cardTerminals[k];
                logger.debug(cardTerminal + " icin BaseSmartCard oluşturulacak.");
                Pair<Long, CardType> slotAndCardType = SmartOp.getSlotAndCardType(cardTerminal);
                Long slotNo = slotAndCardType.getObject1();
                String serialNumber = null; //StringUtil.toString(bsc.getSerial());
                if(useApdu == true && APDUSmartCard.isSupported(cardTerminal))
                {
                    logger.debug("APDU smart kart ile islem yapılacak");
                    bsc = new APDUSmartCard();
                    bsc.openSession(slotNo);
                    serialNumber = StringUtil.toString(bsc.getSerial());
                }
                else
                {
                    logger.debug("PKCS11 smart kart ile islem yapılacak");
                    P11SmartCard  p11 = new P11SmartCard(slotAndCardType.getObject2());
                    CK_TOKEN_INFO tokenInfo = p11.getSmartCard().getTokenInfo(slotNo);
                    serialNumber = String.valueOf(tokenInfo.serialNumber);
                    bsc = p11;
                }

                EBasicSmartCard eBasicSmartCard = null;
                try
                {
                    eBasicSmartCard = basicSmartCards.get(k);
                }
                catch (IndexOutOfBoundsException exc)
                {
                }

                if( (eBasicSmartCard == null) || (eBasicSmartCard.getSerialNumber() != serialNumber) || (eBasicSmartCard.getSlotNo() != k))
                {
                    eBasicSmartCard = null;
                    basicSmartCards.add(k,new EBasicSmartCard(slotNo,serialNumber,bsc,cardTerminal));
                    logger.debug("Basic Smart Card olusturuldu ve listeye eklendi");
                }
            } catch (SmartCardException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                logger.error("Smart Card islem hatası",e);
            } catch (PKCS11Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                logger.error("Smart Card islem hatası",e);
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                logger.error("Smart Card islem hatası",e);
            }
            catch (Exception e){
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                logger.error("Smart Card islem hatası",e);
            }
        }
    }

    private boolean checkCards()
    {
        boolean retValue = true;
        String[] cardTerminals = new String[0];

        cardTerminals = getCardTerminals();
        if(cardTerminals == null)
        {
            return false;
        }

        if(basicSmartCards.size() != cardTerminals.length)
        {
            retValue = false;
        }
        if(retValue)
        {
            if( basicSmartCards == null)
            {
                constructCardList(cardTerminals);
            }
        }
        return retValue;
    }

    public synchronized static ESmartCardManager getInstance()
    {
        if(instance != null)
        {
            if(!instance.checkCards())
            {
                instance = null;
            }
        }
        if(instance == null)
        {
            instance = new ESmartCardManager();
        }
        return instance;
    }

    ArrayList<EBasicSmartCard> basicSmartCards;
    public ArrayList<EBasicSmartCard> getBasicSmartCards() {
        return basicSmartCards;
    }
    boolean  useApdu=false;
}
